package com.zznzzn.myweb.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zznzzn.myweb.exceptions.ServiceException;
import com.zznzzn.myweb.pojo.Record;
import com.zznzzn.myweb.pojo.User;
import com.zznzzn.myweb.service.RecordService;
import com.zznzzn.myweb.service.UserService;
import com.zznzzn.myweb.util.Base64Util;
import com.zznzzn.myweb.util.JWTUtil;
import com.zznzzn.myweb.util.RespHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import javax.websocket.server.PathParam;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;

public class WebSocketHandler extends TextWebSocketHandler {

    @Autowired
    private UserService userService;

    @Autowired
    private RecordService recordService;

    private static final Map<String, WebSocketSession> sessionPool = new HashMap<>();
    private static final Map<String, String> chattingPool = new HashMap<>();
    private static final String USERID = "userid";


    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        JSONObject jsonObject = JSON.parseObject(message.getPayload());
        String fromid = jsonObject.getString("from");
        String type = jsonObject.getString("type");
        String token = jsonObject.getString("token");
        System.out.println("operate : " + type + " from " + fromid);
        User userfrom = userService.getUserById(JWTUtil.getUserId(token));
        //verify token
        if (JWTUtil.verify(token, userfrom.getUuid(), userfrom.getSalt())) {
            switch (type) {
                case "pullAllUser": {
                    try {
                        List<Record> records = recordService.queryRecordsOfUuid(fromid, 100);
                        Set<User> users = new HashSet<>();
                        for (Record re : records) {
                            if (!re.getFromid().equals(fromid)) {
                                users.add(userService.harmless(userService.getUserById(re.getFromid())));
                            }
                            if (!re.getToid().equals(fromid)) {
                                users.add(userService.harmless(userService.getUserById(re.getToid())));
                            }

                        }
                        //统一返回
                        sendOneMessage(fromid, JSON.toJSONString(RespHelper.buildSuccess("pullAllUser", users)));
                    } catch (ServiceException e) {
                        sendOneMessage(fromid, JSON.toJSONString(RespHelper.buildFailure("pullAllUser", e.getMessage())));
                    }
                    break;
                }
                case "pullOneUser": {
                    String to = jsonObject.getString("to");
                    User user = userService.harmless(userService.getUserById(to));
                    sendOneMessage(fromid, JSON.toJSONString(RespHelper.buildSuccess("pullOneUser", user)));
                    break;
                }
                case "pullMore": {
                    String toid1 = jsonObject.getString("to");
                    Date last = jsonObject.getDate("last");
                    List<Record> records1 = recordService.queryRecordsBetweenUuidByAfter(fromid, toid1, last);
                    sendOneMessage(fromid, JSON.toJSONString(RespHelper.buildSuccess("pullMore", records1)));
                    break;
                }
                case "subscribe": {

                    //换一个聊天对象时
                    String toid = jsonObject.getString("to");
                    if (chattingPool.containsKey(fromid)) {
                        chattingPool.replace(fromid, toid);
                    } else {
                        chattingPool.put(fromid, toid);
                    }
                    List<Record> records2 = recordService.queryRecordsBetweenUuidBylimit(fromid, toid, 50);
                    // 将接受的消息设为已读
                    recordService.setReceived(toid, fromid);
                    sendOneMessage(fromid, JSON.toJSONString(RespHelper.buildSuccess("subscribe", records2)));
                    break;
                }
                case "chat": {
                    //new chat record
                    String content = "";
                    try {
                        content = Base64Util.fullDecode(jsonObject.getString("content"));

                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                    String toid = jsonObject.getString("to");
                    Record record = new Record();
                    record.setChatid(Base64Util.newUUID());
                    record.setSendtime(new Date());
                    record.setContent(content);
                    record.setFromid(fromid);
                    record.setToid(toid);
                    if (chattingPool.containsKey(fromid)  //发送者有发送对象
                            && chattingPool.containsKey(toid) //接受者有发送对象
                            && sessionPool.containsKey(fromid) //发送者在线
                            && sessionPool.containsKey(toid) //接受者在线
                            && chattingPool.get(fromid).equals(toid) //发送者将接受者设为接受者
                            && chattingPool.get(toid).equals(fromid) //接受者将发送者设为接受者
                    ) {

                        //当发送者将接受者加入chattingpool 且接受者在线 且接受者也将发送者加入了chattingpool时，直接发送
                        record.setStatus(1);
                        //发送给接受者
                        sendOneMessage(toid, JSON.toJSONString(RespHelper.buildSuccess("chat", record)));
                    }
                    recordService.newRecord(record);
                    //回复给发送者
                    sendOneMessage(fromid, JSON.toJSONString(RespHelper.buildSuccess("chat", record)));
                    System.out.println(record);
                    break;

                }
                case "bye": {
                    chattingPool.remove(fromid);
                    sendOneMessage(fromid, JSON.toJSONString(RespHelper.buildSuccess("bye")));
                    System.out.println("bye!");
                    break;
                }
            }


        } else {
            sendOneMessage(fromid, JSON.toJSONString(RespHelper.buildSuccess("token验证不通过")));
            session.close();
            sessionPool.remove(fromid);
        }

    }

    private void sendOneMessage(String fromid, String msg) {
        if (sessionPool.containsKey(fromid)) {
            try {
                if (sessionPool.get(fromid).isOpen()) {
                    sessionPool.get(fromid).sendMessage(new TextMessage(msg));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String uuid = String.valueOf(session.getAttributes().get(USERID));
        sessionPool.put(uuid, session);
        System.out.println("user " + uuid + " connected , size = " + sessionPool.size());
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        String uuid = String.valueOf(session.getAttributes().get(USERID));
        sessionPool.remove(uuid);
        System.out.println("user " + uuid + " disconnected , size = " + sessionPool.size());
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String uuid = String.valueOf(session.getAttributes().get(USERID));
        if (session.isOpen()) {
            session.close();
        }
        sessionPool.remove(uuid);
        System.out.println("user " + session.getAttributes().get(USERID) + " has error, disconnect , size = " + sessionPool.size());
    }
}
